/**************************************************************************************
*
*	Copyright (C) 2009 - 2012 Brent Andrew O. Chua - See LICENSE.txt for more info.
*		
*	Filename	-	ComponentTransform.cpp
*
*	Comments	-	See ComponentTransform.h
*
**************************************************************************************/
#include "../Include/ComponentTransform.h"
#include "../Include/Engine.h"
#include "../Include/Actor.h"
#include "../Include/EventTransform.h"

namespace Pulse
{
	ComponentTransform::ComponentTransform( Actor *pOwner )
		: IComponent( pOwner )
	{
	}

	ComponentTransform::~ComponentTransform( void )
	{
		//m_pOwner->RemoveListener( EEvent::TRANSFORM, this, &ComponentTransform::OnNewTransform );
	}

	EErrorCode::Type ComponentTransform::Initialize( XMLElementPtr pElem )
	{
		m_position = Vector3::ZERO_VECTOR;
		m_rotation = Vector3::ZERO_VECTOR;
		m_scale = Vector3::ONE_VECTOR;

		m_bUpdateLocal = TRUE;
		m_bUpdateWorld = TRUE;
		m_bSendTransformEvent = TRUE;
		
		m_local = Matrix4x4::IDENTITY;
		m_world = Matrix4x4::IDENTITY;

		m_pEventTransform = new EventTransform;

		//m_pOwner->AddListener( EEvent::TRANSFORM, this, &ComponentTransform::OnNewTransform );

		return EErrorCode::OKAY;
	}

	void ComponentTransform::Update( FLOAT dt )
	{
		// Update local then world matrices
		if ( m_bUpdateLocal )
		{
			Matrix4x4 rotation;

			rotation.BuildRotationPitchYawRoll( m_rotation );
			m_local.BuildScale( m_scale );
			m_local *= rotation;
			m_local.SetTranslation( m_position );

			m_bUpdateLocal = FALSE;
			m_bUpdateWorld = TRUE;
		}

		if ( m_bUpdateWorld )
		{
			Actor *pObject = m_pOwner->GetParent();
			
			if ( pObject )
			{
				m_world = m_local * *pObject->GetTransformWorld();
			}
			else
			{
				m_world = m_local;
			}

			m_bUpdateWorld = FALSE;
			m_bSendTransformEvent =TRUE;
		}

		if ( m_bSendTransformEvent )
		{
			((EventTransform*)&*m_pEventTransform)->SetEventOwner( this );
			((EventTransform*)&*m_pEventTransform)->SetTransform( &m_world );
			m_pOwner->PostEvent( m_pEventTransform );

			m_bSendTransformEvent = FALSE;
		}
	}

	void ComponentTransform::SetTransformWorld( const Matrix4x4 *pTransform )
	{
		// We're setting a new transform given by a world transform.
		// Convert the given world transform to local transform if we have a parent.
		Actor *pParent = GetOwnerUnsafe()->GetParent();

		if ( pParent )
		{
			const Matrix4x4 *pParentTransWorld = pParent->GetTransformWorld();
			Matrix4x4 transformWorldInverse = *pParentTransWorld;
			Matrix4x4 newTransformLocal;
		
			transformWorldInverse.Invert();
			newTransformLocal = *pTransform * transformWorldInverse;
			//SetTransformLocal( &newTransformLocal );
			m_local = newTransformLocal;
		}
		else
		{
			//SetTransformLocal( pTransform );
			m_local = *pTransform;
		}

		m_world = *pTransform;

		// Get orientation attributes
		{
			m_position = m_local.GetTranslation();
			m_rotation = m_local.GetPitchYawRoll();
			m_scale = m_local.GetScale();
		}

		m_bUpdateLocal = FALSE;
		m_bUpdateWorld = FALSE;
		m_bSendTransformEvent = TRUE;
	}

	void ComponentTransform::OnNewTransform( IEvent *pEvent )
	{
		if ( pEvent->GetEventType() == EEvent::TRANSFORM )
		{
			EventTransform *pTransform = (EventTransform*)pEvent;
		
			if ( pTransform->GetEventOwner() != this )
			{

				// TODO: We need to find a way to accumulate all changes and do 
				//	one sweep update from root to leaves. Or some kind of coherency.
				m_world = *pTransform->GetTransform();
			}
		}

	}

}